/*
 * File: ATColorTableController.m
 * Abstract: A controller used by the ATImageTextCell to edit the color property. It is implemented in an abstract enough way to be used by a class other than the cell.
 *
 * Version: 1.0
 *
 * Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
 * Inc. ("Apple") in consideration of your agreement to the following
 * terms, and your use, installation, modification or redistribution of
 * this Apple software constitutes acceptance of these terms.  If you do
 * not agree with these terms, please do not use, install, modify or
 * redistribute this Apple software.
 *
 * In consideration of your agreement to abide by the following terms, and
 * subject to these terms, Apple grants you a personal, non-exclusive
 * license, under Apple's copyrights in this original Apple software (the
 * "Apple Software"), to use, reproduce, modify and redistribute the Apple
 * Software, with or without modifications, in source and/or binary forms;
 * provided that if you redistribute the Apple Software in its entirety and
 * without modifications, you must retain this notice and the following
 * text and disclaimers in all such redistributions of the Apple Software.
 * Neither the name, trademarks, service marks or logos of Apple Inc. may
 * be used to endorse or promote products derived from the Apple Software
 * without specific prior written permission from Apple.  Except as
 * expressly stated in this notice, no other rights or licenses, express or
 * implied, are granted by Apple herein, including but not limited to any
 * patent rights that may be infringed by your derivative works or by other
 * works in which the Apple Software may be incorporated.
 *
 * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
 * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
 * THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
 * OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
 *
 * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
 * MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
 * AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
 * STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Copyright (C) 2009 Apple Inc. All Rights Reserved.
 *
 */

#import "ATColorTableController.h"
#import "ATPopupWindow.h"

@implementation ATColorTableController

+ (ATColorTableController *) sharedColorTableController {
    static ATColorTableController * gSharedColorTableController = nil;

    if (gSharedColorTableController == nil) {
        gSharedColorTableController = [[[self class] alloc] initWithNibName:@"ColorTable" bundle:[NSBundle bundleForClass:[self class]]];
    }
    return gSharedColorTableController;
}

@synthesize delegate = _delegate;
@dynamic selectedColor, selectedColorName;

- (void) dealloc {
    [_colorList release];
    [_colorNames release];
    [_window release];
    [super dealloc];
}

- (void) loadView {
    [super loadView];
    _colorList = [[NSColorList colorListNamed:@"Crayons"] retain];
    _colorNames = [[_colorList allKeys] retain];
    [_tableColorList setIntercellSpacing:NSMakeSize(3, 3)];
    [_tableColorList setTarget:self];
    [_tableColorList setAction:@selector(_tableViewAction:)];
}

- (NSColor *) selectedColor {
    NSString * name = [self selectedColorName];

    if (name != nil) {
        return [_colorList colorWithKey:name];
    } else {
        return nil;
    }
}

- (NSString *) selectedColorName {
    if ([_tableColorList selectedRow] != -1) {
        return [_colorNames objectAtIndex:[_tableColorList selectedRow]];
    } else {
        return nil;
    }
}

- (void) _selectColor:(NSColor *)color {
    // Search for that color in our list
    NSInteger row = 0;

    for (NSString * name in _colorNames) {
        NSColor * colorInList = [_colorList colorWithKey:name];
        if ([color isEqual:colorInList]) {
            break;
        }
        row++;
    }
    _updatingSelection = YES;
    if (row != -1) {
        [_tableColorList scrollRowToVisible:row];
        [_tableColorList selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
    } else {
        [_tableColorList scrollRowToVisible:0];
        [_tableColorList selectRowIndexes:[NSIndexSet indexSet] byExtendingSelection:NO];
    }
    _updatingSelection = NO;
}

- (void) _createWindowIfNeeded {
    if (_window == nil) {
        NSRect viewFrame = self.view.frame;
        // Create and setup our window
        _window = [[ATPopupWindow alloc] initWithContentRect:viewFrame styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
        [_window setReleasedWhenClosed:NO];
        [_window setLevel:NSPopUpMenuWindowLevel];
        [_window setHasShadow:YES];
        [[_window contentView] addSubview:self.view];
        [_window makeFirstResponder:_tableColorList];

        // Make the window have a clear color and be non-opaque for our pop-up animation
        [_window setBackgroundColor:[NSColor clearColor]];
        [_window setOpaque:NO];
    }
}

- (void) _windowClosed:(NSNotification *)note {
    if (_eventMonitor) {
        [NSEvent removeMonitor:_eventMonitor];
        _eventMonitor = nil;
    }
    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:_window];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationDidResignActiveNotification object:nil];
}

- (void) _closeAndSendAction:(BOOL)sendAction {
    [_window close];
    if (sendAction) {
        if ([self.delegate respondsToSelector:@selector(colorTableController:didChooseColor:named:)]) {
            [self.delegate colorTableController:self didChooseColor:self.selectedColor named:self.selectedColorName];
        }
    } else {
        if ([self.delegate respondsToSelector:@selector(didCancelColorTableController:)]) {
            [self.delegate didCancelColorTableController:self];
        }
    }
}

- (void) _windowShouldClose:(NSNotification *)note {
    [self _closeAndSendAction:NO];
}

- (void) editColor:(NSColor *)color locatedAtScreenRect:(NSRect)rect {
    [self _createWindowIfNeeded];
    [self _selectColor:color];
    NSPoint origin = rect.origin;
    NSRect windowFrame = [_window frame];

    // The origin is the lower left; subtract the window's height
    origin.y -= NSHeight(windowFrame);
    // Center the popup window under the rect
    origin.y += floor(NSHeight(rect) / 3.0);
    origin.x -= floor(NSWidth(windowFrame) / 2.0);
    origin.x += floor(NSWidth(rect) / 2.0);

    [_window setFrameOrigin:origin];
    [_window popup];

    // Add some watches on the window and application
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(_windowClosed:)
                                                 name:NSWindowWillCloseNotification
                                               object:_window];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowShouldClose:) name:NSApplicationDidResignActiveNotification object:nil];

    // Start watching events to figure out when to close the window
    NSAssert(_eventMonitor == nil, @"_eventMonitor should not be created yet");
    _eventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask | NSKeyDownMask handler: ^(NSEvent * incomingEvent) {
                         NSEvent * result = incomingEvent;
                         NSWindow * targetWindowForEvent = [incomingEvent window];
                         if (targetWindowForEvent != _window) {
                             [self _closeAndSendAction:NO];
                         } else if ([incomingEvent type] == NSKeyDown) {
                             if ([incomingEvent keyCode] == 53) {
                                 // Escape
                                 [self _closeAndSendAction:NO];
                                 result = nil; // Don't process the event
                             } else if ([incomingEvent keyCode] == 36) {
                                 // Enter
                                 [self _closeAndSendAction:YES];
                                 result = nil;
                             }
                         }
                         return result;
                     }];
}

- (NSInteger) numberOfRowsInTableView:(NSTableView *)tableView {
    return _colorNames.count;
}

- (id) tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
    return [_colorNames objectAtIndex:row];
}

- (void) tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
    NSColor * color = [_colorList colorWithKey:[_colorNames objectAtIndex:row]];

    [cell setColor:color];
}

- (void) _tableViewAction:(id)sender {
    [self _closeAndSendAction:YES];
}

@end

